using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.Data;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace SumerCoreDevOps.Infrastructure.Identity
{
    /// <summary>
    /// Token黑名单服务
    /// 负责管理被撤销的JWT Token
    /// </summary>
    public class TokenBlacklistService
    {
        private readonly FreeSQLProvider _dbProvider;
        private readonly ILogger<TokenBlacklistService> _logger;

        public TokenBlacklistService(FreeSQLProvider dbProvider, ILogger<TokenBlacklistService> _logger)
        {
            this._dbProvider = dbProvider;
            this._logger = _logger;
        }

        /// <summary>
        /// 将Token添加到黑名单
        /// </summary>
        /// <param name="token">JWT Token字符串</param>
        /// <param name="userId">用户ID</param>
        /// <param name="reason">撤销原因</param>
        public async Task BlacklistTokenAsync(string token, long userId, string reason = "User logout")
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = tokenHandler.ReadJwtToken(token);
                
                // 获取Token ID (JTI)
                var jti = jwtToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Jti)?.Value;
                if (string.IsNullOrEmpty(jti))
                {
                    _logger.LogWarning("无法获取Token ID，跳过黑名单操作");
                    return;
                }

                // 获取过期时间
                var expirationClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Exp);
                if (expirationClaim == null || !long.TryParse(expirationClaim.Value, out var expTimestamp))
                {
                    _logger.LogWarning("无法获取Token过期时间，使用默认值");
                    return;
                }

                var expiresAt = DateTimeOffset.FromUnixTimeSeconds(expTimestamp).UtcDateTime;
                
                // 生成Token哈希（用于部分存储）
                var tokenHash = GenerateTokenHash(token);

                // 创建黑名单记录
                var blacklistEntry = new TokenBlacklist
                {
                    TokenId = jti,
                    TokenHash = tokenHash,
                    UserId = userId,
                    ExpiresAt = expiresAt,
                    BlacklistedAt = DateTime.UtcNow,
                    RevocationReason = reason
                };

                // 使用事务保存到数据库
                await _dbProvider.ExecuteInTransactionAsync(async orm =>
                {
                    await orm.Insert(blacklistEntry).ExecuteAffrowsAsync();
                    
                    // 检查是否有重复的Token记录
                    var existingCount = await orm.Select<TokenBlacklist>()
                        .Where(tb => tb.TokenId == blacklistEntry.TokenId && tb.Id != blacklistEntry.Id)
                        .CountAsync();
                    
                    if (existingCount > 0)
                    {
                        _logger.LogWarning("检测到重复的Token黑名单记录: TokenID={TokenId}", blacklistEntry.TokenId);
                    }
                });
                
                _logger.LogInformation("Token已添加到黑名单: 用户ID={UserId}, TokenID={TokenId}", userId, jti);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "将Token添加到黑名单失败");
                throw;
            }
        }

        /// <summary>
        /// 检查Token是否在黑名单中
        /// </summary>
        /// <param name="token">JWT Token字符串</param>
        /// <returns>如果Token在黑名单中则返回true，否则返回false</returns>
        public async Task<bool> IsTokenBlacklistedAsync(string token)
        {
            try
            {
                var tokenHandler = new JwtSecurityTokenHandler();
                var jwtToken = tokenHandler.ReadJwtToken(token);
                
                // 获取Token ID (JTI)
                var jti = jwtToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Jti)?.Value;
                if (string.IsNullOrEmpty(jti))
                {
                    return false;
                }

                // 在事务中查询黑名单，确保数据一致性
                var isBlacklisted = await _dbProvider.ExecuteInTransactionAsync(async orm =>
                {
                    var count = await orm.Select<TokenBlacklist>()
                        .Where(tb => tb.TokenId == jti)
                        .CountAsync();
                    
                    return count > 0;
                });
                
                return isBlacklisted;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查Token黑名单状态失败");
                // 发生错误时默认返回false，避免误判
                return false;
            }
        }

        /// <summary>
        /// 清理过期的黑名单记录
        /// </summary>
        public async Task CleanupExpiredTokensAsync()
        {
            try
            {
                var now = DateTime.UtcNow;
                
                // 使用事务执行清理操作
                var deletedCount = await _dbProvider.ExecuteInTransactionAsync(async orm =>
                {
                    return await orm.Delete<TokenBlacklist>()
                        .Where(tb => tb.ExpiresAt < now)
                        .ExecuteAffrowsAsync();
                });

                if (deletedCount > 0)
                {
                    _logger.LogInformation("已清理 {Count} 条过期的黑名单记录", deletedCount);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清理过期黑名单记录失败");
            }
        }

        /// <summary>
        /// 为Token生成哈希（用于安全存储）
        /// </summary>
        private string GenerateTokenHash(string token)
        {
            using (var sha256 = SHA256.Create())
            {
                var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(token));
                return Convert.ToBase64String(hashBytes);
            }
        }
    }
}